package net.fornwall.eclipsecoder.stats;

import java.util.regex.Pattern;

/**
 * Abstract base class for code generators for different programming languages.
 * 
 * A code generator should be able to map java language constructs to that of
 * another programming language.
 * 
 * Note that this class is just for code generation - support for eclipse
 * integration is from the appropriate language support.
 */
public abstract class CodeGenerator {
	// XXX: Make problemStatement private and use protected getter (and no
	// setter)
	protected ProblemStatement problemStatement;

	public static final String CLASSNAME_TAG = "$CLASSNAME$";

	public static final String DUMMYRETURN_TAG = "$DUMMYRETURN$";

	public static final String METHODNAME_TAG = "$METHODNAME$";

	public static final String METHODPARAMS_TAG = "$METHODPARAMS$";

	public static final String RETURNTYPE_TAG = "$RETURNTYPE$";

	public CodeGenerator(ProblemStatement problemStatement) {
		this.problemStatement = problemStatement;
	}

	/**
	 * Method used for code generation of the solution stub. Should return a
	 * dummy value so that the initial code stub returned by getSolutionStub()
	 * compiles.
	 * 
	 * The $DUMMYRETURN$ tag will be replaced with this value.
	 * 
	 * @return A dummy return value.
	 */
	public abstract String getDummyReturnString();

	/**
	 * Should return the source for a test suite file which tests the solution.
	 */
	public abstract String getTestsSource();

	/**
	 * Get the code template for the language. The code template should contain
	 * the relevant tags which will be substituted.
	 * 
	 * <p>
	 * The code template should be settable from a preference page and should
	 * default to a reasonable value.
	 * 
	 * <p>
	 * This method is not intended to be overridden by subclasses unless there
	 * is special need.
	 * 
	 * @return the code template with the variables replaced
	 */
	public String getSolutionStub(String codeTemplate) {
		return codeTemplate.replaceAll(Pattern.quote(CLASSNAME_TAG),
				problemStatement.getSolutionClassName()).replaceAll(
				Pattern.quote(METHODNAME_TAG),
				problemStatement.getSolutionMethodName()).replaceAll(
				Pattern.quote(METHODPARAMS_TAG), getMethodParamsString())
				.replaceAll(Pattern.quote(DUMMYRETURN_TAG),
						getDummyReturnString()).replaceAll(
						Pattern.quote(RETURNTYPE_TAG),
						getTypeString(problemStatement.getReturnType()));
	}

	/**
	 * Should return the replacement for the $METHODPARAMS$ tag. Utility method
	 * for use in getSolutionStub().
	 */
	protected String getMethodParamsString() {
		StringBuilder builder = new StringBuilder();
		for (int i = 0; i < problemStatement.getParameterNames().size(); i++) {
			if (i != 0) {
				builder.append(", ");
			}
			String typeString = getTypeString(problemStatement
					.getParameterTypes().get(i));
			if (typeString.length() > 0) {
				builder.append(typeString);
				builder.append(' ');
			}
			builder.append(problemStatement.getParameterNames().get(i));
		}
		return builder.toString();
	}

	/**
	 * Map a java language class to the matching language type.
	 * 
	 * Implementations for scripting languages without explicit types should
	 * return an empty string.
	 * 
	 * @param type
	 *            The java class to map.
	 * @return The matching language type.
	 */
	public abstract String getTypeString(Class<?> type);
}
